package com.cskaoyan.javse.oop3._2inner._1member._1basic;

/**
 * @description: 成员内部类的访问特点
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/


/**
 * 在理解成员内部类的访问特点,先明确以下两点:
 *      1.内部类和外围类是"hxd",它们之间的访问不受访问权限限制,包括私有
 *      2.成员内部类对象依赖于外围类对象而存在
 *          思考:
 *              a.成员内部类类中的成员方法中,怎么去访问外围类的成员?
 *                  外围类成员想要访问,需要外围类对象
 *                  成员内部类类中的成员方法中,有没有外围类对象? --->
 *                      成员内部类类中的成员方法中,有没有内部类自身对象? 是有的 -->
 *                      成员内部类要想有对象,必须先有外围类对象 -->
 *                      成员内部类类中的成员方法中,既有自身对象,也有外围类对象
 *                   成员内部类类中的成员方法中,怎么去访问外围类的成员? ---> 直接访问
 *
 *              b.外围类的成员方法中,怎么去访问成员内部类成员?
 *                  访问内部类成员--> 需要内部类对象 --> 而外围类的成员方法中,没有内部类对象 --> 没有就创建对象
 *                  外围类的成员方法中,创建内部类对象,如何创建? ---> 外围类成员方法中已经存在外围类对象 --->
 *                      直接创建内部类对象即可,然后用对象去访问就可以了
 *
 *              c.外围类的静态成员方法中,怎么去访问成员内部类成员?
 *                  外围类的静态成员方法中,没有自身对象 -->
 *                  要想访问内部类成员 --> 需要先创建外围类对象,再创建内部类对象
 *
 * > 成员内部类的访问特点
 * > - 成员内部类内部访问外围类成员
 *      需要在成员内部类的成员方法中访问外围类成员,因为外围类对象已经存在,所以可以直接访问,直接写成员的名字就可以了
 *      特殊情况下,当内部类成员和外围类成员同名时,如果仍然用成员名直接访问,访问的结果是内部类自身成员(就近原则)
 *      这时怎么去访问外围类成员呢?
 *      在成员内部类的成员方法中,自身对象用this指向,外围类对象用"外围类类名.this"指向
 *      如果出现同名情况,直接用外围类类名.this.成员名访问,即得到外围类成员
 *      如果出现局部变量,内部类成员变量,外围类成员变量三者都同名(假如都是a)的情况,
 *      用就近原则的a访问的是局部变量的
 *      用this.a访问的内部类自己的成员变量
 *      用外围类类名.this.a访问的是外围类的成员变量
 *
 * 最后如果全局常量同名了,就用类名点去区分
 *
 * > - 外围类访问成员内部类成员
 *      1.外围类的成员方法中
 *          需要创建成员内部类对象
 *          怎么创建?
 *          因为外围类对象已经存在,用this指向
 *          所以可以直接创建内部类对象
 *          语法: new 内部类类名(参数);
 *          有对象后,直接用对象名点访问成员即可
 *
 *          如果有同名的情况,用内部类对象名访问的就是内部类的成员,反之不写对象名或者写this访问的都是外围类的成员
 *
 *      2.外围类的静态成员方法中
 *          需要创建成员内部类对象
 *          怎么创建?
 *          需要先创建外围类对象,再创建内部类对象
 *          并且内部类对象是在外围类基础上完成创建的
 *          得到两个对象后,用谁的对象名访问得到的就是谁的成员
 *
 *          语法:
 *              MemberInnerClazz mic2 = new EnclosedClazz().new MemberInnerClazz();
 *
 * > - 外部类中访问成员内部类成员
 *      首先,内部类多数都是私有的,多数情况下外部类是没有内部类的访问权限,这一条仅供了解
 *      前提: 首先要有外围类权限,其次还要有内部类权限
 *      其次: 外部类和内部类没有关系,它们之间的访问受访问权限的限制,私有的成员外部类无法访问
 *      最后需要创建内部类对象
 *      怎么创建?
 *      需要先创建外围类对象,然后在外围类对象基础上创建成员内部类对象
 *      需要注意的是在外部类中创建成员内部类对象,在接收对象时,需要明确指出该内部类属于哪个外围类,使用语法: 外围类类名.成员内部类类名
 *      在总体上,创建对象的语法:
 *      EnclosedClazz.MemberInnerClazz mic2 = new EnclosedClazz().new MemberInnerClazz();(是万能的公式)
 *      创建对象后,使用对象名访问成员即可!
 *
 * > - 成员内部类访问外部类成员（了解）
 *      直接创建对象即可,但是受访问权限限制
 *
 */
public class Demo {
    public static void main(String[] args) {
        //静态方法和非静态方法访问方式一样
        EnclosedClazz ec = new EnclosedClazz();
        EnclosedClazz.MemberInnerClazz mic = ec.new MemberInnerClazz();

        //二合一
        EnclosedClazz.MemberInnerClazz mic2 = new EnclosedClazz().new MemberInnerClazz();

        mic2.testInner();
    }
}

//外围类
class EnclosedClazz {
    int a = 10;
    private int b;
    static int c = 20;
    private static final int D = 30;

    public void test() {

        System.out.println("外围类成员方法");


        //直接创建内部类对象
        MemberInnerClazz mic = new MemberInnerClazz();
        //上一条语句,如果写全是这样的
        MemberInnerClazz mic2 = this.new MemberInnerClazz();
        System.out.println(mic.a);
        System.out.println(a);
        System.out.println(this.a);

    }

    public static void testStatic() {
        System.out.println("外围类静态成员方法");
        //先创建外围类对象
        EnclosedClazz ec = new EnclosedClazz();
        //再在ec的基础上创建内部类对象
        MemberInnerClazz mic = ec.new MemberInnerClazz();
        //上述语句写法可以二合一
        MemberInnerClazz mic2 = new EnclosedClazz().new MemberInnerClazz();
        System.out.println(ec.a);
        System.out.println(mic.a);
    }

    //定义成员内部类
    class MemberInnerClazz {
        //定义成员变量
        int a = 100;
        private int b;
        static final int D = 300;
        //定义成员方法
        public void testInner() {
            System.out.println(EnclosedClazz.this.a);
            System.out.println(b);
            System.out.println(EnclosedClazz.c);
            System.out.println(EnclosedClazz.D);
            System.out.println(MemberInnerClazz.D);
        }

        public void test(int a) {
            //请在test方法中同时访问局部变量a,内部类成员变量a,外围类成员变量a
            System.out.println(a);
            System.out.println(this.a);
            System.out.println(EnclosedClazz.this.a);
        }

    }


}
